﻿﻿package 
{
    import flash.display.Bitmap;
    import flash.display.Graphics;
    import flash.display.Loader;
    import flash.display.MovieClip;
    import flash.events.*;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.net.URLRequest;

    public class Planet extends MovieClip {
        { //member variables
        public var radius :Number;
        protected var gravity :Number;
        protected var swf :SuperStar;//the game
                
        private var loader:Loader;
                
        public var velX :Number = 0;//velocity
        public var velY :Number = 0;
        public var immune :Boolean = false;//affected by gravity?
        public var hasGravity:Boolean = false;//pulls on shit?
        public var area:Number = 0;
        //public var hungerTimer:Timer;//NOM NOM NOMM yummy stars
        private var gravIncrement:int = 0;
        public var isSafe:Boolean = false;//in the safe zone, bitch
        public var isFrozen:Boolean = false;
        public var isShieldOn:Boolean = false;
        public var isBeingDragged:Boolean = false;
                
        public var dir:Point;//these two are used for preserving momentum after a star is dragged by the player
        public var pos:Point;
                
        public var isFreezePowerup:Boolean = false;
        public var isShieldPowerup:Boolean = false;
        public var isRegularStar:Boolean = true;
        public var isAlien:Boolean = false;
        private var powerupProb:int = 10;//probability that a star spawns as a powerup (any type)
        }

        public function Planet(radius :Number, hasGravity:Boolean, main :SuperStar, loader:Loader = null)
        {
            super();
            this.radius = radius;
            this.area = (3.14159 * radius * radius);
            this.hasGravity = hasGravity;//whether or not it pulls on other objects
            this.swf    = main;
                        
            if (hasGravity) { //if it pulls on other objects
                this.calculateGravity(1);//calculate how much it pulls
                this.addEventListener(Event.ENTER_FRAME, pull);//pull on other objects in each frame
                //hungerTimer = new Timer(5000, 0);//how long until it gets hungrier? (gravity increases until a star falls in)
                //hungerTimer.addEventListener(TimerEvent.TIMER, increaseGravity);
                //hungerTimer.start();
                this.loader = loader;
                this.draw();//draw the object on screen
            } else {//if it doesn't have gravity, then it will move around on the screen and be pulled by gravity bearing objects
                this.addEventListener(Event.ENTER_FRAME, move);
                if (swf.randomNumber(1, 100) <= powerupProb) {//powerupProb that the star will be a powerup
                    isRegularStar = false;
                    if (swf.randomNumber(1, 100) <= 50) {//freeze power up
                        isFreezePowerup = true;
                    } else {//shield powerup
                        isShieldPowerup = true;
                    }
                    this.draw();
                } else {//its a regular star, so load the star image
                    this.loader = new Loader();
                    this.loader.contentLoaderInfo.addEventListener(Event.COMPLETE, this.draw);
                    this.loader.load(new URLRequest("images/star.png"));
                }
                                
                                
            }
                        
                        
        }
        
                
        //while being dragged, keep track of which direction it is moving, so momentum is maintained after being released by the player
        public function updatePosition(e:Event) {
            pos = new Point(swf.stage.mouseX, swf.stage.mouseY);
        }
                
        //as the void gets hungrier, gradually increase its gravity until a star falls in, then reset back to normal
        private function increaseGravity(e:Event) {
            this.calculateGravity(++gravIncrement);
        }
                
        //decide how much gravity the object has.
        //pixels_per_second: how far should an object being pulled by this object move towards it every second?
        //Higher pixels_per_second = stronger gravity
        protected function calculateGravity(pixels_per_second:Number) :void
        {
            // Let's default average gravity based on an average-px diameter planet
            // Higher average value = lower gravity overall
            var average:Number = 60;
            var grav_ratio :Number = (this.radius * 2) / average;
                        
            // Increase in gravity should be 1 pixel per second (pixels per second / frame rate)
            var pixels_per_frame :Number  = pixels_per_second / swf.stage.frameRate;
                        
            this.gravity = pixels_per_frame * grav_ratio;
            //trace("Gravity = " + this.gravity);
        }
                
        //draw the object as a circle with the indicated radius
        //TODO: Once we have art for the objects, this function will need to be re-written
        protected function draw(e:Event = null) :void
        {
            var g :Graphics = this.graphics;
            g.lineStyle(1, 0xff0000, 1);
            if (isFreezePowerup) {//colour it blue
                g.beginFill(0x0666a4);
                g.drawCircle(0, 0, this.radius);
            } else if (isShieldPowerup) {//colour it purple
                g.beginFill(0x9956a2);
                g.drawCircle(0, 0, this.radius);
            } else if (hasGravity) {//is a void
                loader.scaleX = 2 * radius / 465;
                loader.scaleY = 2 * radius / 465;
                loader.x = this.x - this.radius;
                loader.y = this.y - this.radius - 10;
                addChild(loader);
            } else if(loader != null) {//its a regular star 
                loader.scaleX = 2 * radius / 400;
                loader.scaleY = 2 * radius / 400;
                loader.x -= this.radius;
                loader.y -= this.radius;
                addChild(loader);
            } else {//just in case, draw it as a gray circle
                g.beginFill(0x999999);
                g.drawCircle(0, 0, this.radius);
            }
        }


                
        //if this has gravity, then it pulls on all other objects on the screen towards its center (unless they are immune)
        protected function pull(e :Event) :void
        {
            for (var i :int = 0; i < this.swf.objects.length; i++)//go through all objects on screen
            {
                var o :Object = this.swf.objects[i];
                                
                if (o != this && o.immune == false)//don't pull on myself, and don't pull on objects that are immune
                {       
                    var voidCenter:Point = new Point(this.x, this.y);
                    var starCenter:Point = new Point(o.x, o.y);
                                        
                    var xDiff:Number = voidCenter.x - starCenter.x;
                    var yDiff:Number = voidCenter.y - starCenter.y;

                    var dist :Number = Math.sqrt((xDiff * xDiff) + (yDiff * yDiff));//distance between centers of the void and the object
                                        
                    var modifier :Number = this.gravity;
                    for (var x :Number = 0; x < dist; x += 15)
                    {
                        modifier *= .99;//decrease gravity strength by 1% every x pixels in every direction
                    }
                                        
                    var xChange :Number = (modifier / dist) * xDiff;
                    var yChange :Number = (modifier / dist) * yDiff;
                                        
                    o.velX += xChange;//change the direciton of the object so it moves towards the void
                    o.velY += yChange;
                                
                }
            }
		}
                
                
        //if an object falls into this one, increase its radius and therefore its gravity
        public function increaseRadius() {
            if (hasGravity) {//only works if this object has gravity
				//hungerTimer.stop();//reset hunger level
				this.removeEventListener(Event.ENTER_FRAME, pull);//stop pulling on everything else until new void is created
							
				var newRadius = this.radius + 5;//increase the radius
									
				if (newRadius >= swf.stage.stageHeight / 2) swf.losing = true;
									
				swf.removeChild(this);//remove the old void
				var index:int = -1;
				for (var i = 0; i < swf.objects.length; i++) if (swf.objects[i] == this) index = i;
				if (index != -1) swf.objects.splice(index, 1);//remove the old void from the list of objects
				var newESV:Planet = new Planet(newRadius, true, swf, loader);//create a new void with increased radius
				newESV.y = swf.stage.stageHeight / 2;
				newESV.x = newESV.y;
				newESV.immune = true;//make sure it isn't pulled on by other objects (or itself)
											
				swf.objects.push(newESV);//add to the list of objects
				swf.addChild(newESV);//display the new void on screen
				swf.esv = newESV;//change the variable to point to the new void object
											
				//trace("ESV Radius = " + swf.esv.radius);

                                
            }
        }
                
        //decrease the radius of the void
        //works the exact same way as increaseRadius(), except a multiplier is used to change the amount of the decrease
        public function decreaseRadius(multiplier:int) {
            if (hasGravity) {
                this.removeEventListener(Event.ENTER_FRAME, pull);
                swf.removeChild(this);
                var index:int = -1;
                for (var i = 0; i < swf.objects.length; i++) if (swf.objects[i] == this) index = i;
                if (index != -1) swf.objects.splice(index, 1);
                                
                var newRadius;
                                
                if (multiplier <= 3) newRadius = this.radius - multiplier * 3;
                else if (multiplier <= 5) newRadius = this.radius - multiplier * 5;
                else if (multiplier <= 7) newRadius = this.radius - multiplier * 6;
                else newRadius = this.radius - multiplier * 8;
                                
                                
                if (newRadius <= 0) {//game has been won
                    newRadius = 0;
                    //hungerTimer.stop();
                    swf.winning = true;
                } else {
                    var newESV:Planet = new Planet(newRadius, true, swf, loader);
                    newESV.y = swf.stage.stageHeight / 2;
                    newESV.x = newESV.y;
                    newESV.immune = true;
                                        
                    swf.objects.push(newESV);
                    swf.addChild(newESV);
                    swf.esv = newESV;
                }
            }
        }
                
        //move a star on the screen according to its velocity, calculated previously
        protected function move(e: Event) :void
        {
            //if the stars are moving too fast to be able to click on them, then slow them down (but only do it while they are off-screen so the player can't tell)
            //this part slows down in the x-grid
            if ((Math.abs(this.velX) >= 8) && ((this.x >= swf.stage.stageWidth + this.radius) || (this.x <= 0 - this.radius))) {
                this.velX = this.velX * 0.5;
                //trace("Horizontal slow down");//just so we know how often it happens
            }
                        
            //same thing for the y-grid
            if ((Math.abs(this.velY) >= 8) && ((this.y >= swf.stage.stageHeight + this.radius) || (this.y <= 0 - this.radius))) {
                this.velY = this.velY * 0.5;
                //trace("Vertical slow down");
            }
                        
            //if the star is safe, then prevent it from leaving the safe zone
            if (isSafe) {
                if (Math.abs(velX) >= 10) velX *= 0.5; //stop it from speeding up indefinitely inside the box
                if (Math.abs(velY) >= 10) velY *= 0.5;
                if (x + velX >= swf.safeZone.x - this.radius) velX = -velX;//bounce off the walls in the safe zone
                if (x + velX <= swf.safeZone.x - swf.safeZone.width + this.radius) velX = -velX;
                if (y + velY >= swf.safeZone.y - this.radius) velY = -velY;
                if (y + velY <= swf.safeZone.y - swf.safeZone.height + this.radius) velY = -velY;
                                
                //be eaten if it collides with an alien
                if(swf.safeZone.hasAlien) {
                    var alien:Planet = swf.safeZone.alien;
                    if(alien != this) {
                        var starCenter:Point = new Point(this.x, this.y);
                        var alienCenter:Point = new Point(alien.x, alien.y);
                        var dx:Number = starCenter.x - alienCenter.x;
                        var dy:Number = starCenter.y - alienCenter.y;
                        var dist:Number = Math.sqrt(dx * dx + dy * dy);
                                                
                        if (dist <= (this.radius + alien.radius)) {
                            var index:int = -1;
                            for (var i = 0; i < swf.safeStars.length; i++) {
                                if (swf.safeStars[i] == this) index = i;
                            }
                                                        
                            var alreadyEmpty:Boolean = false;
                            if (swf.safeStars.length == 0) alreadyEmpty = true;
                            if (index != -1) {
                                swf.safeStars.splice(index, 1);
                                swf.removeChild(this);
                            }
                            if (swf.safeStars.length == 0 && !alreadyEmpty) swf.removeChild(swf.shrinkButton);
                            alreadyEmpty = null;
                        }
                    }
                }
            }
                        
            this.x += this.velX;//move the star according to its current velocity
            this.y += this.velY;
                        
            //rotate the star so the top is always facing the ESV
            var starCenter:Point = new Point(this.x, this.y);
            var voidCenter:Point = new Point(swf.esv.x, swf.esv.y);
                        
            var angle:Number = Math.atan2(starCenter.y - voidCenter.y, starCenter.x - voidCenter.x) * (180 / Math.PI);
            if (angle < 0) {
                angle += 360;
            }
            this.rotation = angle;
                        
            //check if the star has collided with the EVEVVVVILL SPACE VOIIID
            //if it does collide, remove the star and increase the radius of the ESV
            if (isInsideVoid(this)) {
                if(!swf.esv.isShieldOn) {
                    //swf.esv.calculateGravity(1);//reset hunger back to normal
                    //gravIncrement = 0;
                    this.removeEventListener(Event.ENTER_FRAME, move);//stop moving the star, as it doesn't exist anymore!
                    swf.removeChild(this);//hide the star
                    var index:int = -1;
                    for (var i = 0; i < swf.objects.length; i++) {//remove the star from the list of objects
                        if (swf.objects[i] == this) index = i;
                    }
                    if (index != -1) swf.objects.splice(index, 1);
                                        
                    swf.esv.increaseRadius();//make the void bigger
                } else {//star should bounce off the void instead of falling in
                    //TODO: this currently does not bounce properly, in the future it would be nice if they bounced correctly using angles etc
                    velX = -velX;
                    velY = -velY;
                }
            }
                        
        }
                
        //calculate if a star has collided with the void
        public function isInsideVoid(p:Planet):Boolean {
            //find the centers of the star in question as well as the void
            var voidCenter:Point = new Point(swf.esv.x, swf.esv.y);
            var starCenter:Point = new Point(p.x, p.y);
                        
            var dx:Number = starCenter.x - voidCenter.x + velX;//calculate the distance between the centers
            var dy:Number = starCenter.y - voidCenter.y + velY;
            var dist:Number = Math.sqrt(dx * dx + dy * dy);//pythagoras was one smart mother fucker
                        
            if (dist <= (swf.esv.radius + p.radius) && swf.winning == false) {
                return true;
            } else return false;
        }
                
        //run this if the star is being dragged by the player
        public function drag(e:Event) {
            swf.removeChild(this);//make sure the star isn't underneath anything else
            swf.addChild(this);
                        
            this.addEventListener(MouseEvent.MOUSE_UP, releaseDrag);//listen for the player to release the mouse
            this.immune = true;//stop the void from pulling on it while it is being dragged
            this.isBeingDragged = true;
            this.velX = 0;//stop the star from moving on its own
            this.velY = 0;
            this.dir = new Point();//useful for preserving momentum from the mouse when it is released
            this.addEventListener(Event.ENTER_FRAME, updatePosition);//every frame update the stars position so its direction of movement and speed can be calculated
            this.startDrag();//follow the mouse until released
        }
                
        //run this after the player releases the drag
        public function releaseDrag(e:Event) {
            this.stopDrag();
            this.isBeingDragged = false;
            this.removeEventListener(MouseEvent.MOUSE_UP, releaseDrag);
            if (!this.isFrozen) this.immune = false;//allow the void to pull on the star again
            this.removeEventListener(Event.ENTER_FRAME, updatePosition);//stop updating its position every frame
            this.dir = new Point(swf.stage.mouseX - this.pos.x, swf.stage.mouseY - this.pos.y);//calculate direction of movement and velocity while it was being dragged
            if (!this.isFrozen) {
                this.velX = this.dir.x;//make the star continue to move in the proper direction and velocity after it is released
                this.velY = this.dir.y;
            }
                        
            if (swf.safeZone.isInSafeZone(this)) {
                if (this.isAlien) {
                    swf.safeStars.push(this);
                    swf.safeZone.hasAlien = true;
                    swf.safeZone.alien = this;
                }
                                
				var prob:int;
									
				if (swf.safeStars.length <= 2) prob = 0;
				else if (swf.safeStars.length <= 3) prob = 45;
				else if (swf.safeStars.length <= 4) prob = 45;
				else if (swf.safeStars.length <= 5) prob = 50;
				else prob = 70;
									
				//given a certain probability, and there being a certain number of stars already safe,
				//this star might turn into an alien and start eating other stars in the safe zone
				if (this.isRegularStar && swf.randomNumber(1,100) <= prob && !swf.safeZone.hasAlien) {
					convertToAlien();
					swf.safeStars.push(this);
					swf.safeZone.hasAlien = true;
					swf.safeZone.alien = this;
				}
																	
				if (!this.isSafe) swf.incrementScore(null, 25);//increment the score, but not if the star was already safe
				this.isSafe = true;//if the player dropped it in the safe zone, then it is safe
				if (this.isFreezePowerup) {
					if (swf.safeFreezePowerups.length == 0) swf.addChild(swf.freezeButton);
					swf.safeFreezePowerups.push(this);
			   } else if (this.isShieldPowerup) {
					if (swf.safeShieldPowerups.length == 0) swf.addChild(swf.shieldButton);
					swf.safeShieldPowerups.push(this);
				} else if(this.isRegularStar) {
					if (swf.safeStars.length == 0) swf.addChild(swf.shrinkButton);
					swf.safeStars.push(this);
				}
            } else {
                if (this.isSafe && this.isAlien) {
                    swf.safeZone.hasAlien = false;
                    swf.safeZone.alien = null;
                }
                                
                if (this.isSafe) swf.incrementScore(null, -25);//if the player pulled the star out of the safe zone, take away some points
                                
                this.isSafe = false;//if it was safe, but the player removed it from the safe zone, then it is no longer safe (oopsies!)
                                
                if (this.isFreezePowerup) {
                    var index:int = -1;
                    for (var i = 0; i < swf.safeFreezePowerups.length; i++) {
                        if (swf.safeFreezePowerups[i] == this) index = i;
                    }
                    var alreadyEmpty:Boolean = false;
                    if (swf.safeFreezePowerups.length == 0) alreadyEmpty = true;
                    if (index != -1) swf.safeFreezePowerups.splice(index, 1);
                    if (swf.safeFreezePowerups.length == 0 && !alreadyEmpty) swf.removeChild(swf.freezeButton);
                    alreadyEmpty = null;
                } else if (this.isShieldPowerup) {
                    var index:int = -1;
                    for (var i = 0; i < swf.safeShieldPowerups.length; i++) {
                        if (swf.safeShieldPowerups[i] == this) index = i;
                    }
                    var alreadyEmpty:Boolean = false;
                    if (swf.safeShieldPowerups.length == 0) alreadyEmpty = true;
                    if (index != -1) swf.safeShieldPowerups.splice(index, 1);
                    if (swf.safeShieldPowerups.length == 0 && !alreadyEmpty) swf.removeChild(swf.shieldButton);
                    alreadyEmpty = null;
                } else {
                    var index:int = -1;
                    for (var i = 0; i < swf.safeStars.length; i++) {
                        if (swf.safeStars[i] == this) index = i;
                    }
                    var alreadyEmpty:Boolean = false;
                    if (swf.safeStars.length == 0) alreadyEmpty = true;
                    if (index != -1) swf.safeStars.splice(index, 1);
                    if (swf.safeStars.length == 0 && !alreadyEmpty) swf.removeChild(swf.shrinkButton);
                        alreadyEmpty = null;
                }
            }
        }
                
        //convert this star into an alien and start eating shit!
        private function convertToAlien() {
            this.isRegularStar = false;
            this.isAlien = true;
                        
            removeChild(loader);
            var g:Graphics = this.graphics;
            g.lineStyle(1, 0xff0000, 1);
            g.beginFill(0xFFFFFF);//color it white
            g.drawCircle(0, 0, this.radius);
        }
    }
}